#
# = nessus-xmlrpc.rb: communicate with Nessus(4.2+) over XML RPC interface
#
# Author:: Vlatko Kosturjak
#
# (C) Vlatko Kosturjak, Kost. Distributed under GPL and BSD license (dual).
# 
# == What is this library? 
# 
# This library is used for communication with Nessus over XML RPC interface. 
# You can start, stop, pause and resume scan. Watch progress and status of scan, 
# download report, etc.
#
# == Requirements
# 
# Required libraries are standard Ruby libraries: uri, net/https and rexml/document. 
#
# == Usage:
# 
#  require 'nessus-xmlrpc'
#  n=NessusXMLRPC::NessusXMLRPC.new('https://localhost:8834','user','pass');
#  if n.logged_in
# 	id,name = n.policy_get_first
# 	puts "using policy ID: " + id + " with name: " + name
# 	uid=n.scan_new(id,"textxmlrpc","127.0.0.1")
#	puts "status: " + n.scan_status(uid)
# 	while not n.scan_finished(uid)
# 		sleep 10
# 	end
#	content=n.report_file_download(uid)
# 	File.open('report.xml', 'w') {|f| f.write(content) }
#  end

require 'uri'
require 'net/https'
require 'rexml/document'

# NessusXMLRPC module
# 
# Usage:
# 
#  require 'nessus-xmlrpc'
#  n=NessusXMLRPC::NessusXMLRPC.new('https://localhost:8834','user','pass');
#  if n.logged_in
# 	id,name = n.policy_get_first
# 	uid=n.scan_new(id,"textxmlrpc","127.0.0.1")
#	puts "status: " + n.scan_status(uid)
#  end
#
# Check NessusXMLRPCrexml for description of methods implemented 
# (for both NessusXMLRPCnokogiri and NessusXMLRPCrexml).

module NessusXMLRPC 

  # Class which uses standard REXML to parse nessus XML RPC replies.
  class NessusXMLRPC
    # initialize object: try to connect to Nessus Scanner using URL, user and password
    #
    # Usage:
    #
    #  n=NessusXMLRPC::NessusXMLRPC.new('https://localhost:8834','user','pass');
    def initialize(url,user,password)
      if url == ''
        @nurl="https://localhost:8834/"
      else
        if url =~ /\/$/
          @nurl=url
        else
          @nurl=url + "/"
        end
      end
      @token=''
      #login(user,password)
    end

    # checks if we're logged in correctly
    #
    # returns: true if logged in, false if not
    #
    # Usage:
    #
    #  n=NessusXMLRPC::NessusXMLRPC.new('https://localhost:8834','user','pass');
    #  if n.logged_in
    #	puts "Logged in"
    #  else
    #	puts "Error"
    #  end

    def logged_in
      if @token == ''
        return false
      else
        return true
      end
    end

    # send standard Nessus XML request and check
    #
    # returns: rexml/document root
    def nessus_request(uri, post_data)
      body=nessus_http_request(uri, post_data)
      # puts response.body
      docxml = REXML::Document.new(body)
      begin
        status = docxml.root.elements['status'].text
      rescue
        puts("Error connecting/logging to the server!")
        return
      end
      if status == "OK"
        return docxml
      else
        return ''
      end
    end

    # send standard Nessus HTTP request and check
    #
    # returns: body of response
    def nessus_http_request(uri, post_data)
      url = URI.parse(@nurl + uri)
      request = Net::HTTP::Post.new( url.path )
      request.set_form_data( post_data )
      if not defined? @https
        @https = Net::HTTP.new( url.host, url.port )
        @https.use_ssl = true
        @https.verify_mode = OpenSSL::SSL::VERIFY_NONE
      end
      # puts request
      begin
        response = @https.request( request )
      rescue
        puts("error connecting to server: #{@nurl} with URI: #{uri}")
        exit
      end
      # puts response.body
      return response.body
    end
  
    # login with user & password and sets object-wide @token, @name and @admin
    def login(user, password)
      post = { "login" => user, "password" => password }
      docxml=nessus_request('login', post)
      if docxml == ''
        @token=''
      else
        @token = docxml.root.elements['contents'].elements['token'].text
        @name = docxml.root.elements['contents'].elements['user'].elements['name'].text
        @admin = docxml.root.elements['contents'].elements['user'].elements['admin'].text
        # puts "Got token:" + @token
        return @token
      end
      
    end
  
    #checks to see if the user is an admin
    def is_admin
      if @admin == "TRUE"
        return true
      end
      return false
    end
  
    # initiate new scan with policy id, descriptive name and list of targets
    #
    # returns: uuid of scan
    #
    # Usage:
    #
    #  n=NessusXMLRPC::NessusXMLRPC.new('https://localhost:8834','user','pass');
    #  if n.logged_in
    # 	id,name = n.policy_get_first
    # 	puts "using policy ID: " + id + " with name: " + name
    # 	uid=n.scan_new(id,"textxmlrpc","127.0.0.1")
    #  end
    def scan_new(policy_id,scan_name,target)
      post= { "token" => @token, "policy_id" => policy_id, "scan_name" => scan_name, "target" => target }
      docxml=nessus_request('scan/new', post)
      if docxml == ''
        return ''
      else
        uuid=docxml.root.elements['contents'].elements['scan'].elements['uuid'].text
        return uuid
      end
    end

    # get uids of scans
    #
    # returns: array of uids of active scans
    def scan_list_uids
      post= { "token" => @token }
      docxml = nil
      docxml=nessus_request('scan/list', post)
      if docxml.nil?
        return
      end
      uuids=Array.new
      docxml.root.elements['contents'].elements['scans'].elements['scanList'].each_element('//scan') {|scan| uuids.push(scan.elements['uuid'].text) }
      return uuids
    end

    # get hash of active scan data
    #
    # returns: array of hash of active scans
    def scan_list_hash
      post= { "token" => @token }
      docxml = nil
      docxml=nessus_request('scan/list', post)
      if docxml.nil?
        return
      end
      scans=Array.new
      docxml.root.elements['contents'].elements['scans'].elements['scanList'].each_element('//scan') {|scan|
        entry=Hash.new
        entry['id']=scan.elements['uuid'].text if scan.elements['uuid']
        entry['name']=scan.elements['readableName'].text if scan.elements['readableName']
        entry['owner']=scan.elements['owner'].text if scan.elements['owner']
        entry['start']=scan.elements['start_time'].text if scan.elements['start_time']
        entry['status']=scan.elements['status'].text if scan.elements['status']
        entry['current']=scan.elements['completion_current'].text if scan.elements['completion_current']
        entry['total']=scan.elements['completion_total'].text if scan.elements['completion_total']
        scans.push(entry)
      }
      return scans
    end
    
    def template_list_hash
      post= { "token" => @token }
      docxml = nessus_request('scan/list', post)
      templates = Array.new
      docxml.elements.each('/reply/contents/templates/template') { |template|
        entry=Hash.new
        entry['name']=template.elements['name'].text if template.elements['name']
        entry['pid']=template.elements['policy_id'].text if template.elements['policy_id']
        entry['rname']=template.elements['readableName'].text if template.elements['readableName']
        entry['owner']=template.elements['owner'].text if template.elements['owner']
        entry['target']=template.elements['target'].text if template.elements['target']
        templates.push(entry)
      }
      return templates
    end
  
    # get hash of policies
    #
    # returns: array of hash of policies
    def policy_list_hash
      post= { "token" => @token }
      docxml = nil
      docxml=nessus_request('scan/list', post)
      if docxml.nil?
        return
      end
      policies=Array.new
      docxml.elements.each('/reply/contents/policies/policies/policy') { |policy|
        entry=Hash.new
        entry['id']=policy.elements['policyID'].text if policy.elements['policyID']
        entry['name']=policy.elements['policyName'].text if policy.elements['policyName']
        entry['comment']=policy.elements['policyComments'].text if policy.elements['policyComments']
        policies.push(entry)
      }
      return policies
    end
  
    # get hash of reportss
    #
    # returns: array of hash of templates
    def report_list_hash
      post= { "token" => @token }
      docxml = nil
      docxml=nessus_request('report/list', post)
      if docxml.nil?
        return
      end
      #puts docxml
      reports=Array.new
      docxml.root.elements['contents'].elements['reports'].each_element('//report') {|report|
        entry=Hash.new
        entry['id']=report.elements['name'].text if report.elements['name']
        entry['name']=report.elements['readableName'].text if report.elements['readableName']
        entry['status']=report.elements['status'].text if report.elements['status']
        entry['timestamp']=report.elements['timestamp'].text if report.elements['timestamp']
        reports.push(entry)
      }
      return reports
    end

    # get policy by textname and return policyID
    #
    # returns: policyID
    def policy_get_id(textname)
      post= { "token" => @token }
      docxml = nil
      docxml=nessus_request('policy/list', post)
      if docxml.nil?
        return
      end
      docxml.root.elements['contents'].elements['policies'].each_element('//policy') {|policy|
        if policy.elements['policyName'].text == textname
          return policy.elements['policyID'].text
        end
      }
      return ''
    end

    # get first policy from server and returns: policyID, policyName
    #
    # returns: policyID, policyName
    def policy_get_first
      post= { "token" => @token }
      docxml = nil
      docxml=nessus_request('policy/list', post)
      if docxml.nil?
        return
      end
      docxml.root.elements['contents'].elements['policies'].each_element('//policy') {|policy|
        return policy.elements['policyID'].text, policy.elements['policyName'].text
      }
    end

    # get list of policy IDs
    #
    # returns: array of all policy uids
    def policy_list_uids
      post= { "token" => @token }
      docxml = nil
      docxml=nessus_request('policy/list', post)
      if docxml.nil?
        return
      end
      pids=Array.new
      docxml.root.elements['contents'].elements['policies'].each_element('//policy') { |policy|
        pids.push(policy.elements['policyID'].text) }
      return pids
    end

    # stop scan identified by scan_uuid
    def scan_stop(uuid)
      post= { "token" => @token, "scan_uuid" => uuid }
      docxml = nil
      docxml=nessus_request('scan/stop', post)
      if docxml.nil?
        return
      end
      return docxml
    end
  
    # stop all active scans
    #
    # Usage:
    #
    #  n=NessusXMLRPC::NessusXMLRPC.new('https://localhost:8834','user','pass');
    #  if n.logged_in
    #	n.scan_stop_all
    #  end
    def scan_stop_all
      b=scan_list_uids
      b.each {|uuid|
        scan_stop(uuid)
      }
      return b
    end
  
    # pause scan identified by scan_uuid
    def scan_pause(uuid)
      post= { "token" => @token, "scan_uuid" => uuid }
      docxml = nil
      docxml=nessus_request('scan/pause', post)
      if docxml.nil?
        return
      end
      return docxml
    end
  
    # pause all active scans
    #
    # Usage:
    #
    #  n=NessusXMLRPC::NessusXMLRPC.new('https://localhost:8834','user','pass');
    #  if n.logged_in
    #	n.scan_pause_all
    #  end
    def scan_pause_all
      b=scan_list_uids
      b.each {|uuid|
        scan_pause(uuid)
      }
      return b
    end
  
    # remove scan identified by uuid
    def scan_resume(uuid)
      post= { "token" => @token, "scan_uuid" => uuid }
      docxml = nil
      docxml=nessus_request('scan/resume', post)
      if docxml.nil?
        return
      end
      return docxml
    end
    # resume all active scans
    #
    # Usage:
    #
    #  n=NessusXMLRPC::NessusXMLRPC.new('https://localhost:8834','user','pass');
    #  if n.logged_in
    #	n.scan_resume_all
    #  end
    def scan_resume_all
      b=scan_list_uids
      b.each {|uuid|
        scan_resume(uuid)
      }
      return b
    end

    # check status of scan identified by uuid
    def scan_status(uuid)
      post= { "token" => @token, "report" => uuid }
      docxml = nil
      docxml=nessus_request('report/list', post)
      if docxml.nil?
        return
      end
      docxml.root.elements['contents'].elements['reports'].each_element('//report') { |report|
        if report.elements['name'].text == uuid
          return (report.elements['status'].text)
        end
      }
      return ''
    end

    # check if scan is finished (completed to be exact) identified by uuid
    def scan_finished(uuid)
      status=scan_status(uuid)
      if status == "completed"
        return true
      else
        return false
      end
    end
  
    # get report by reportID and return XML file
    #
    # returns: XML file of report (nessus v2 format)
    def report_file_download(report)
      post= { "token" => @token, "report" => report }
      file = nil
      file=nessus_http_request('file/report/download', post)
      if file.nil?
        return
      end
      return file
    end

    # get report by reportID and return XML file (version 1)
    #
    # returns: XML file of report (nessus v1 format)
    def report_file1_download(report)
      post= { "token" => @token, "report" => report, "v1" => "true" }
      
      file=nessus_http_request('file/report/download', post)
      
      return file
    end
  
    # delete report by report ID
    def report_delete(id)
      post= { "token" => @token, "report" => id }
      docxml = nil
      docxml=nessus_request('report/delete', post)
      if docxml.nil?
        return
      end
      return docxml
    end

    # get list of names of policies
    #
    # returns: array of names
    def policy_list_names
      post= { "token" => @token }
      docxml = nil
      docxml=nessus_request('policy/list', post)
      if docxml.nil?
        return
      end
      list = Array.new
      docxml.root.elements['contents'].elements['policies'].each_element('//policy') {|policy|
        list.push policy.elements['policyName'].text
      }
      return list
    end

    # get data for each host for a particular report
    #
    #
    # returns: array of hashes:
    #		hostname
    #		severity
    #		severityCount0
    #		severityCount1
    #		severityCount2
    #		severityCount3
    #		scanProgressCurrent
    #		scanprogressTotal
    def report_hosts(report_id)
      post= { "token" => @token, "report" => report_id }
      docxml = nil
      docxml=nessus_request('report/hosts', post)
      if docxml.nil?
        return
      end
      hosts=Array.new
      docxml.elements.each('/reply/contents/hostList/host') do |host|
        entry=Hash.new
        entry['hostname'] = host.elements['hostname'].text if host.elements['hostname']
        entry['severity'] = host.elements['severity'].text if host.elements['severity']
        sevs=Array.new
        host.elements.each('severityCount/item') do |item|
          sevs.push item.elements['count'].text if item.elements['count']
        end
        entry['sev0'] = sevs[0] if sevs[0]
        entry['sev1'] = sevs[1] if sevs[1]
        entry['sev2'] = sevs[2] if sevs[2]
        entry['sev3'] = sevs[3] if sevs[3]
        entry['current'] = host.elements['scanProgressCurrent'].text if host.elements['scanProgressCurrent']
        entry['total'] = host.elements['scanProgressTotal'].text if host.elements['scanProgressTotal']
        hosts.push(entry)
      end
      return hosts
    end
  
    def report_host_ports(report_id,host)
      post= { "token" => @token, "report" => report_id, "hostname" => host }
      docxml = nil
      docxml=nessus_request('report/ports', post)
      if docxml.nil?
        return
      end
      ports=Array.new
      docxml.elements.each('/reply/contents/portList/port') do |port|
        entry=Hash.new
        entry['portnum'] = port.elements['portNum'].text if port.elements['portNum']
        entry['protocol'] = port.elements['protocol'].text if port.elements['protocol']
        entry['severity'] = port.elements['severity'].text if port.elements['severity']
        entry['svcname'] = port.elements['svcName'].text if port.elements['svcName']
        sevs=Array.new
        port.elements.each('severityCount/item') do |item|
          sevs.push item.elements['count'].text if item.elements['count']
        end
        entry['sev0'] = sevs[0] if sevs[0]
        entry['sev1'] = sevs[1] if sevs[1]
        entry['sev2'] = sevs[2] if sevs[2]
        entry['sev3'] = sevs[3] if sevs[3]
        ports.push(entry)
      end
      return ports
    end
  
    def report_host_port_details(report_id,host,port,protocol)
      post= { "token" => @token, "report" => report_id, "hostname" => host, "port" => port, "protocol" => protocol }
      docxml = nil
      docxml=nessus_request('report/details', post)
      if docxml.nil?
        return
      end
      reportitems=Array.new
      docxml.elements.each('/reply/contents/portDetails/ReportItem') do |rpt|
        entry=Hash.new
        cve = Array.new
        bid = Array.new
        entry['port'] = rpt.elements['port'].text if rpt.elements['port']
        entry['severity'] = rpt.elements['severity'].text if rpt.elements['severity']
        entry['pluginID'] = rpt.elements['pluginID'].text if rpt.elements['pluginID']
        entry['pluginName'] = rpt.elements['pluginName'].text if rpt.elements['pluginName']
        entry['cvss_base_score'] = rpt.elements['data'].elements['cvss_base_score'].text if rpt.elements['data'].elements['cvss_base_score']
        entry['exploit_available'] = rpt.elements['data'].elements['exploit_available'].text if rpt.elements['data'].elements['exploit_available']
        if rpt.elements['data'].elements['cve']
          rpt.elements['data'].elements['cve'].each do |x|
            cve.push rpt.elements['data'].elements['cve'].text
          end
        end
        entry['cve'] = cve if cve
        entry['risk_factor'] = rpt.elements['data'].elements['risk_factor'].text if rpt.elements['data'].elements['risk_factor']
        entry['cvss_vector'] = rpt.elements['data'].elements['cvss_vector'].text if rpt.elements['data'].elements['cvss_vector']
        entry['solution'] = rpt.elements['data'].elements['solution'].text if rpt.elements['data'].elements['solution']
        entry['description'] = rpt.elements['data'].elements['description'].text if rpt.elements['data'].elements['description']
        entry['synopsis'] = rpt.elements['data'].elements['synopsis'].text if rpt.elements['data'].elements['synopsis']
        entry['see_also'] = rpt.elements['data'].elements['see_also'].text if rpt.elements['data'].elements['see_also']
        if rpt.elements['data'].elements['bid']
          rpt.elements['data'].elements['bid'].each do |y|
            bid.push rpt.elements['data'].elements['bid'].text
          end
        end
        entry['bid'] = bid if bid
        #entry['xref'] = rpt.elements['data'].elements['xref'].text # multiple of these
        entry['plugin_output'] = rpt.elements['data'].elements['plugin_output'].text if rpt.elements['data'].elements['plugin_output']
        reportitems.push(entry)
      end
      return reportitems
    end

    # get host details for particular host identified by report id
    #
    # returns: severity, current, total
    def report_get_host(report_id,hostname)
      post= { "token" => @token, "report" => report_id }
      docxml = nil
      docxml=nessus_request('report/hosts', post)
      if docxml.nil?
        return
      end
      docxml.elements.each('/reply/contents/hostList/host') do |host|
        if host.elements['hostname'].text == hostname
          severity = host.elements['severity'].text
          current = host.elements['scanProgressCurrent'].text
          total = host.elements['scanProgressTotal'].text
          return severity, current, total
        end
      end
    end
  
    # gets a list of each plugin family and the number of plugins for that family.
    def plugins_list
      post= { "token" => @token }
      docxml =  nil
      docxml=nessus_request('plugins/list', post)
      if docxml.nil?
        return
      end
      plugins=Array.new
      docxml.root.elements['contents'].elements['pluginFamilyList'].each_element('//family') { |plugin|
        entry=Hash.new
        entry['name']=plugin.elements['familyName'].text
        entry['num']=plugin.elements['numFamilyMembers'].text
        plugins.push(entry)
      }
      return plugins
    end
  
    #returns a list of users, if they are an admin and their last login time.
    def users_list
      post= { "token" => @token }
      docxml = nil
      docxml=nessus_request('users/list', post)
      if docxml.nil?
        return
      end
      users=Array.new
      docxml.root.elements['contents'].elements['users'].each_element('//user') { |user|
        entry=Hash.new
        entry['name']=user.elements['name'].text
        entry['admin']=user.elements['admin'].text
        entry['lastlogin']=user.elements['lastlogin'].text
        users.push(entry)
      }
      return users
    end
  
    # returns basic data about the feed type and versions.
    def feed
      post = { "token" => @token }
      docxml = nil
      docxml = nessus_request('feed', post)
      if docxml.nil?
        return
      end
      feed = docxml.root.elements['contents'].elements['feed'].text
      version = docxml.root.elements['contents'].elements['server_version'].text
      web_version = docxml.root.elements['contents'].elements['web_server_version'].text
      return feed, version, web_version
    end
  
    def user_add(user,pass)
      post= { "token" => @token, "login" => user, "password" => pass }
      docxml = nil
      docxml = nessus_request('users/add', post)
      if docxml.nil?
        return
      end
      return docxml
    end
  
    def user_del(user)
      post= { "token" => @token, "login" => user }
      docxml = nil
      docxml = nessus_request('users/delete', post)
      if docxml.nil?
        return
      end
      return docxml
    end
  
    def user_pass(user,pass)
      post= { "token" => @token, "login" => user, "password" => pass }
      docxml = nil
      docxml = nessus_request('users/chpasswd', post)
      if docxml.nil?
        return
      end
      return docxml
    end
  
    def plugin_family(fam)
      post = { "token" => @token, "family" => fam }
      docxml = nil
      docxml = nessus_request('plugins/list/family', post)
      if docxml.nil?
        return
      end
      family=Array.new
      docxml.elements.each('/reply/contents/pluginList/plugin') { |plugin|
        entry=Hash.new
        entry['filename'] = plugin.elements['pluginFileName'].text if plugin.elements['pluginFileName']
        entry['id'] = plugin.elements['pluginID'].text if plugin.elements['pluginID']
        entry['name'] = plugin.elements['pluginName'].text if plugin.elements['pluginName']
        family.push(entry)
      }
      return family
    end
  
    def policy_del(pid)
      post= { "token" => @token, "policy_id" => pid }
      docxml = nil
      docxml = nessus_request('policy/delete', post)
      if docxml.nil?
        return
      end
      return docxml
    end
  
    def report_del(rid)
      post= { "token" => @token, "report" => rid }
      docxml = nil
      docxml = nessus_request('report/delete', post)
      if docxml.nil?
        return
      end
      return docxml
    end
  
    def plugin_detail(pname)
      post = { "token" => @token, "fname" => pname }
      docxml = nil
      docxml = nessus_request('plugins/description', post)
      if docxml.nil?
        return
      end
      entry=Hash.new
      docxml.elements.each('reply/contents/pluginDescription') { |desc|
        entry['name'] = desc.elements['pluginName'].text
        entry['id'] = desc.elements['pluginID'].text
        entry['family'] = desc.elements['pluginFamily'].text
        desc.elements.each('pluginAttributes') { |attr|
          entry['exploit_ease'] = attr.elements['exploitability_ease'].text if attr.elements['exploitability_ease']
          entry['cvss_temporal_vector'] = attr.elements['cvss_temporal_vector'].text if attr.elements['cvss_temporal_vector']
          entry['solution'] = attr.elements['solution'].text if attr.elements['solution']
          entry['cvss_temporal_score'] = attr.elements['cvss_temporal_score'].text if attr.elements['cvss_temporal_score']
          entry['risk_factor'] = attr.elements['risk_factor'].text if attr.elements['risk_factor']
          entry['description'] = attr.elements['description'].text if attr.elements['description']
          entry['plugin_publication_date'] = attr.elements['plugin_publication_date'].text if attr.elements['plugin_publication_date']
          entry['cvss_vector'] = attr.elements['cvss_vector'].text if attr.elements['cvss_vector']
          entry['synopsis'] = attr.elements['synopsis'].text if attr.elements['synopsis']
          entry['exploit_available'] = attr.elements['exploit_available'].text if attr.elements['exploit_available']
          entry['plugin_modification_date'] = attr.elements['plugin_modification_date'].text if attr.elements['plugin_modification_date']
          entry['cvss_base_score'] = attr.elements['cvss_base_score'].text if attr.elements['cvss_base_score']
        }
      }
      return entry
    end
  
    def server_prefs
      post= { "token" => @token }
      docxml = nil
      docxml = nessus_request('preferences/list', post)
      if docxml.nil?
        return
      end
      prefs = Array.new
      docxml.elements.each('/reply/contents/ServerPreferences/preference') { |pref|
        entry=Hash.new
        entry['name'] = pref.elements['name'].text if pref.elements['name']
        entry['value']= pref.elements['value'].text if pref.elements['value']
        prefs.push(entry)
      }
      return prefs
    end
  
    def plugin_prefs
      post= { "token" => @token }
      docxml = nil
      docxml = nessus_request('plugins/preferences', post)
      if docxml.nil?
        return
      end
      prefs = Array.new
      docxml.elements.each('/reply/contents/PluginsPreferences/item') { |pref|
        entry=Hash.new
        entry['fullname'] = pref.elements['fullName'].text if pref.elements['fullName']
        entry['pluginname'] = pref.elements['pluginName'].text if pref.elements['pluginName']
        entry['prefname'] = pref.elements['preferenceName'].text if pref.elements['preferenceName']
        entry['preftype'] = pref.elements['preferenceType'].text if pref.elements['preferenceType']
        entry['prefvalues'] = pref.elements['preferenceValues'].text if pref.elements['preferenceValues']
        prefs.push(entry)
      }
      return prefs
    end
  end # end of NessusXMLRPC::Class

end # of Module

